#include "show_file.h"

#include "xxx_info.h"
#include "xxx_mapping.h"
#include <sys/mount.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <libgen.h>
#include <libmount/libmount.h>



/*
 * Show file
 *  @info: correctly loaded xxx_info
 *  @filepath: shown file (abc.xxx), the entry of hidden file.
 *  return:
 *      On success, return zero.
*/
// WARNING: This function should be atomic, eithor success or error.
int show_file(struct xxx_info *info, const char *filepath)
{
    if (info == NULL || info->fs == NULL || filepath == NULL)
        return -1;

    // get full path, dir path, filename
    char dirpath[PATH_MAX];
    char filename[PATH_MAX];

    if (three_in_one(info, filepath, filename, dirpath) != 0)
        return 1;

    struct stat file_st = {};
    if (stat(filepath, &file_st) != 0)
        return 2;

    struct stat dir_st = {};
    if (stat(dirpath, &dir_st) != 0)
        return 4;

    // link: show hiddden file
    struct xxx_mapping_item *item = find_mapping(info, (ext2_ino_t)file_st.st_ino);

    if (item == NULL)
        return 5;

    ext2fs_link(info->fs, (ext2_ino_t)dir_st.st_ino, item->hidden_entry.name,
                item->hidden_entry.hidden_ino_t, item->hidden_entry.filetype);

    // remount, flush Linux kernel cache
    mount("ignore", info->mountpoint, "ignore", MS_REMOUNT, "rw");

    // WARNING: cannot use stdio to operate target fs when it's opened.
    ext2fs_close(info->fs);

    // unlink: remove shown file
    remove(filepath);

    // reopen fs
    ext2fs_open(info->devpath, EXT2_FLAG_RW, 0, 0, unix_io_manager, &info->fs);

    delete_mapping(item);

    return 0;
}

